﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using System.Web;
using NHibernate.Context;
using System.Reflection;
using NHibernate.Event;

namespace Mindfor.Web.Data
{
	/// <summary>
	/// Provides functions to access data in SQL Server 2008.
	/// </summary>
	public class SqlServer2008DataProvider : IDataProvider,
		IPreUpdateEventListener, IPreInsertEventListener, IPreDeleteEventListener,
		IPostUpdateEventListener, IPostInsertEventListener, IPostDeleteEventListener
	{
		/// <summary>
		/// Gets configured session factory.
		/// </summary>
		public ISessionFactory SessionFactory { get; private set; }

		/// <summary>
		/// Initializes data provider.
		/// </summary>
		public SqlServer2008DataProvider(string connectionString)
		{
			SessionFactory = Fluently.Configure()
				.Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString))
				.CurrentSessionContext<WebSessionContext>()
				.Mappings(x => x.FluentMappings.AddFromMindforAssemblies())
				.ExposeConfiguration(cfg => 
				{
					cfg.EventListeners.PreInsertEventListeners = new IPreInsertEventListener[] { this };
					cfg.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] { this };
					cfg.EventListeners.PreDeleteEventListeners = new IPreDeleteEventListener[] { this };
					cfg.EventListeners.PostInsertEventListeners = new IPostInsertEventListener[] { this };
					cfg.EventListeners.PostUpdateEventListeners = new IPostUpdateEventListener[] { this };
					cfg.EventListeners.PostDeleteEventListeners = new IPostDeleteEventListener[] { this };
				})
				.BuildSessionFactory();
		}

		/// <summary>
		/// Gets current data session. Returns null if no current data session.
		/// </summary>
		public ISession GetCurrentSession()
		{
			try
			{
				return SessionFactory.GetCurrentSession();
			}
			catch
			{
				return null;
			}
		}

		public bool OnPreInsert(PreInsertEvent @event)
		{
			IPreCommit commitable = @event.Entity as IPreCommit;
			if (commitable != null)
				commitable.OnPreInsert(@event.Session);
			return false;
		}

		public bool OnPreUpdate(PreUpdateEvent @event)
		{
			IPreCommit commitable = @event.Entity as IPreCommit;
			if (commitable != null)
				commitable.OnPreUpdate(@event.Session);
			return false;
		}

		public bool OnPreDelete(PreDeleteEvent @event)
		{
			IPreCommit commitable = @event.Entity as IPreCommit;
			if (commitable != null)
				commitable.OnPreDelete(@event.Session);
			return false;
		}

		public void OnPostDelete(PostDeleteEvent @event)
		{
			IPostCommit commitable = @event.Entity as IPostCommit;
			if (commitable != null)
				commitable.OnPostDelete(@event.Session);
		}

		public void OnPostUpdate(PostUpdateEvent @event)
		{
			IPostCommit commitable = @event.Entity as IPostCommit;
			if (commitable != null)
				commitable.OnPostUpdate(@event.Session);
		}

		public void OnPostInsert(PostInsertEvent @event)
		{
			IPostCommit commitable = @event.Entity as IPostCommit;
			if (commitable != null)
				commitable.OnPostInsert(@event.Session);
		}
	}
}
